﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Pay.Core {
	public static class MerchantX509Cert {
		// Methods
		private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) {
			RSACryptoServiceProvider provider2;
			MemoryStream input = new MemoryStream(privkey);
			BinaryReader binr = new BinaryReader(input);
			ushort num2 = 0;
			int count = 0;
			try {
				num2 = binr.ReadUInt16();
				if (num2 == 0x8130) {
					binr.ReadByte();
				} else if (num2 == 0x8230) {
					binr.ReadInt16();
				} else {
					return null;
				}
				if (binr.ReadUInt16() != 0x102) {
					return null;
				}
				if (binr.ReadByte() != 0) {
					return null;
				}
				count = GetIntegerSize(binr);
				byte[] buffer = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer2 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer3 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer4 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer5 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer6 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer7 = binr.ReadBytes(count);
				count = GetIntegerSize(binr);
				byte[] buffer8 = binr.ReadBytes(count);
				CspParameters parameters = new CspParameters {
					Flags = CspProviderFlags.UseMachineKeyStore
				};
				RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x400, parameters);
				RSAParameters parameters2 = new RSAParameters {
					Modulus = buffer,
					Exponent = buffer2,
					D = buffer3,
					P = buffer4,
					Q = buffer5,
					DP = buffer6,
					DQ = buffer7,
					InverseQ = buffer8
				};
				provider.ImportParameters(parameters2);
				provider2 = provider;
			} catch (Exception) {
				provider2 = null;
			} finally {
				binr.Close();
			}
			return provider2;
		}

		private static int GetIntegerSize(BinaryReader binr) {
			byte num = 0;
			byte num2 = 0;
			byte num3 = 0;
			int num4 = 0;
			if (binr.ReadByte() != 2) {
				return 0;
			}
			num = binr.ReadByte();
			if (num == 0x81) {
				num4 = binr.ReadByte();
			} else if (num == 130) {
				num3 = binr.ReadByte();
				num2 = binr.ReadByte();
				byte[] buffer2 = new byte[4];
				buffer2[0] = num2;
				buffer2[1] = num3;
				byte[] buffer = buffer2;
				num4 = BitConverter.ToInt32(buffer, 0);
			} else {
				num4 = num;
			}
			while (binr.ReadByte() == 0) {
				num4--;
			}
			binr.BaseStream.Seek(-1L, SeekOrigin.Current);
			return num4;
		}

		private static byte[] GetPem(string type, byte[] data) {
			string str = Encoding.UTF8.GetString(data);
			string str2 = string.Format("-----BEGIN {0}-----\n", type);
			string str3 = string.Format("-----END {0}-----", type);
			int startIndex = str.IndexOf(str2) + str2.Length;
			int index = str.IndexOf(str3, startIndex);
			return Convert.FromBase64String(str.Substring(startIndex, index - startIndex));
		}

		private static RSACryptoServiceProvider LoadCertificateFile(string keystr, string filename) {
			using (FileStream stream = File.OpenRead(filename)) {
				byte[] buffer = new byte[stream.Length];
				byte[] privkey = null;
				stream.Read(buffer, 0, buffer.Length);
				if (buffer[0] != 0x30) {
					privkey = GetPem(keystr, buffer);
				}
				try {
					return DecodeRSAPrivateKey(privkey);
				} catch (Exception) {
				}
				return null;
			}
		}

		public static string Sign(string data, string privateKeyPath) {
			byte[] bytes = Encoding.UTF8.GetBytes(data);
			return str2HexStr(LoadCertificateFile("RSA PRIVATE KEY", privateKeyPath).SignData(bytes, "SHA1"));
		}

		public static string Sign(string data, string privateKeyPath, string password) {
			byte[] bytes = Encoding.UTF8.GetBytes(data);
			X509Certificate2 certificate = new X509Certificate2(privateKeyPath, password);
			byte[] rgbHash = new SHA1CryptoServiceProvider().ComputeHash(bytes);
			RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter();
			formatter.SetKey(certificate.PrivateKey);
			formatter.SetHashAlgorithm("SHA1");
			return str2HexStr(formatter.CreateSignature(rgbHash));
		}

		public static string str2HexStr(byte[] bs) {
			string str = "0123456789ABCDEF";
			StringBuilder builder = new StringBuilder("");
			foreach (byte num in bs) {
				char ch = str[num & 15];
				char ch2 = str[(num >> 4) & 15];
				builder.Append(ch2);
				builder.Append(ch);
			}
			return builder.ToString().Trim().ToLower();
		}

		private static byte[] str2HexStr(string hexString) {
			hexString = hexString.Replace(" ", "");
			if ((hexString.Length % 2) != 0) {
				hexString = hexString + " ";
			}
			byte[] buffer = new byte[hexString.Length / 2];
			for (int i = 0; i < buffer.Length; i++) {
				buffer[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 0x10);
			}
			return buffer;
		}

		public static bool VerifySign(string data, string publicKeyPath, string sign) {
			byte[] bytes = Encoding.UTF8.GetBytes(data);
			byte[] signature = str2HexStr(sign);
			X509Certificate2 certificate = new X509Certificate2(publicKeyPath);
			RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
			provider.FromXmlString(certificate.PublicKey.Key.ToXmlString(false));
			return provider.VerifyData(bytes, "SHA1", signature);
		}
	}
}
